home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / pine3.07 / pico / pico.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-14  |  14.5 KB  |  605 lines

  1. /*
  2.  * Program:    Main Pine Composer routines
  3.  *
  4.  * Modifier:    Michael Seibel
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: mikes@cac.washington.edu
  11.  *
  12.  * Date:    Nov 1989
  13.  * Last Edited:    9 September 1991
  14.  *
  15.  * Copyright 1991 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made
  24.  * available "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  *
  35.  * WEEMACS/PICO NOTES:
  36.  *
  37.  * 01 Nov 89 - MicroEmacs 3.6 vastly pared down and becomes a function call 
  38.  *            weemacs() and plugged into the Pine mailer.  Lots of unused
  39.  *           MicroEmacs code laying around.
  40.  *
  41.  * 17 Jan 90 - weemacs() became weemacs() the composer.  Header editing
  42.  *           functions added.
  43.  *
  44.  * 09 Sep 91 - weemacs() renamed pico() for the PIne COmposer.
  45.  *
  46.  */
  47.  
  48.  
  49. /*
  50.  * This program is in public domain; written by Dave G. Conroy.
  51.  * This file contains the main driving routine, and some keyboard processing
  52.  * code, for the MicroEMACS screen editor.
  53.  *
  54.  * REVISION HISTORY:
  55.  *
  56.  * 1.0  Steve Wilhite, 30-Nov-85
  57.  *      - Removed the old LK201 and VT100 logic. Added code to support the
  58.  *        DEC Rainbow keyboard (which is a LK201 layout) using the the Level
  59.  *        1 Console In ROM INT. See "rainbow.h" for the function key defs
  60.  *      Steve Wilhite, 1-Dec-85
  61.  *      - massive cleanup on code in display.c and search.c
  62.  *
  63.  * 2.0  George Jones, 12-Dec-85
  64.  *      - Ported to Amiga.
  65.  *
  66.  * 3.0  Daniel Lawrence, 29-Dec-85
  67.  *    16-apr-86
  68.  *    - updated documentation and froze development for 3.6 net release
  69.  */
  70.  
  71. #include        <stdio.h>
  72. #include    <setjmp.h>
  73.  
  74. /* make global definitions not external */
  75. #define    maindef
  76.  
  77. #include    "osdep.h"    /* operating system dependent includes */
  78. #include        "estruct.h"    /* global structures and defines */
  79. #include    "efunc.h"    /* function declarations and name table    */
  80. #include    "pico.h"    /* PIne COmposer definitions */
  81. #include    "edef.h"    /* global definitions */
  82. #include    "ebind.h"    /* default key bindings */
  83.  
  84.  
  85. /*
  86.  * function key mappings
  87.  */
  88. static int pfkm[12][2] = {
  89.     { F1,  (CTRL|'G')},
  90.     { F2,  (CTRL|'X')},
  91.     { F3,  (CTRL|'C')},
  92.     { F4,  (CTRL|'J')},
  93.     { F5,  (CTRL|'R')},
  94.     { F6,  (CTRL|'W')},
  95.     { F7,  (CTRL|'Y')},
  96.     { F8,  (CTRL|'V')},
  97.     { F9,  (CTRL|'K')},
  98.     { F10, (CTRL|'U')},
  99.     { F11, (CTRL|'O')},
  100. #ifdef    SPELLER
  101.     { F12, (CTRL|'T')}
  102. #else
  103.     { F12, (CTRL|'D')}
  104. #endif
  105. };
  106.  
  107.  
  108. /*
  109.  * common place for the various functions in pico() to jump to when ready
  110.  * for pico() to return...
  111.  */
  112. jmp_buf    finstate;        /* stack environment to return codes */
  113.  
  114.  
  115. /*
  116.  * pico - the main routine for Pine's composer.
  117.  *
  118.  */
  119. pico(pm)
  120. PICO *pm;
  121. {
  122.     register int    c;
  123.     register int    f;
  124.     register int    n;
  125.     register BUFFER *bp;
  126.     int      i;
  127.     int      viewflag = FALSE;        /* are we starting in view mode? */
  128.     char     bname[NBUFN];        /* buffer name of file to read */
  129.     extern   struct on_display ods;
  130.  
  131.     Pmaster = pm;
  132.     gmode |= pm->pine_flags;/* high 4 bits rsv'd by pine composer */
  133.  
  134.     vtinit();                /* Init Displays.      */
  135.  
  136.     strcpy(bname, "main");        /* default buffer name */
  137.     edinit(bname);            /* Buffers, windows.   */
  138.  
  139.     InitMailHeader(pm);            /* init mail header structure */
  140.  
  141.     /* setup to process commands */
  142.     lastflag = 0;            /* Fake last flags.     */
  143.     curbp->b_mode |= gmode;        /* and set default modes*/
  144.  
  145.     if(pm->messagebuf[0] != '\0'){    /* any text to start with? */
  146.     readbuf(&pm->messagebuf);
  147.     gotobob(FALSE, 1);
  148.     }
  149.  
  150.     switch(setjmp(finstate)){        /* prepare for/handle final events */
  151.       case COMP_EXIT :
  152.     vttidy();            /* already confirmed */
  153.     packheader();
  154.     return((packbuf(&pm->messagebuf, &pm->messbuflen,
  155.             pm->pine_flags&P_LOCALLF)| COMP_EXIT));
  156.       case COMP_SUSPEND :
  157.     vttidy();            /* suspend it! */
  158.     packheader();
  159.     return((packbuf(&pm->messagebuf, &pm->messbuflen, 
  160.             pm->pine_flags&P_LOCALLF)| COMP_SUSPEND));
  161.       case COMP_CANCEL :
  162.     writeout(MAILGRAVE);        /* already confirmed */
  163.     vttidy();
  164.     zotedit();
  165.     return(COMP_CANCEL);
  166.  
  167.       case COMP_GOTHUP:
  168.     /* 
  169.      * pack up and let caller know that we've received a SIGHUP
  170.      */
  171.     if(ComposerEditing)        /* expand addr if needed */
  172.       resolve_niks(ods.cur_e);
  173.     vttidy();
  174.     packheader();
  175.     return((packbuf(&pm->messagebuf, &pm->messbuflen, 
  176.             pm->pine_flags&P_LOCALLF)| COMP_GOTHUP));
  177.  
  178.       default:
  179.     break;
  180.     }
  181.  
  182.     if(pm->pine_flags&P_REPLY){        /* begin editing the header? */
  183.     ArrangeHeader();        /* line up pointers */
  184.     }
  185.     else{
  186.     update();            /* paint screen, */
  187.     HeaderEditor(0, 0);        /* start editing... */
  188.     }
  189.  
  190.     while(1){
  191.     update();            /* Fix up the screen    */
  192.  
  193.     c = GetKey();    
  194.  
  195.     if(c == NODATA || time_to_check()){    /* new mail ? */
  196.         if((*Pmaster->newmail)(&i, 0, c == NODATA ? 0 : 2) >= 0){
  197.         mlerase();
  198.         (*Pmaster->showmsg)(c);
  199.         mpresf = 1;
  200.         }
  201.  
  202.         if(i || mpresf)        /* let em know cursor moved */
  203.           movecursor(0, 0);
  204.  
  205.         if(c == NODATA)        /* no op, getkey timed out */
  206.           continue;
  207.     }
  208.  
  209.     if (mpresf != FALSE) {        /* message stay around only  */
  210.         if (mpresf++ > MESSDELAY)    /* so long! */
  211.           mlerase();
  212.     }
  213.  
  214.     f = FALSE;            /* vestigial */
  215.     n = 1;
  216.     
  217.     execute(normal(c, pfkm, 2), f, n);    /* Do it.               */
  218.     }
  219. }
  220.  
  221. /*
  222.  * Initialize all of the buffers and windows. The buffer name is passed down
  223.  * as an argument, because the main routine may have been told to read in a
  224.  * file by default, and we want the buffer name to be right.
  225.  */
  226.  
  227. /*
  228.  * For the pine composer, we don't want to take over the whole screen
  229.  * for editing.  the first some odd lines are to be used for message 
  230.  * header information editing.
  231.  */
  232. edinit(bname)
  233. char    bname[];
  234. {
  235.     register BUFFER *bp;
  236.     register WINDOW *wp;
  237.  
  238.     if(Pmaster)
  239.       func_init();
  240.  
  241.     bp = bfind(bname, TRUE, 0);             /* First buffer         */
  242.  
  243.     if(Pmaster == NULL)
  244.       blistp = bfind("[List]", TRUE, BFTEMP); /* Buffer list buffer   */
  245.  
  246.     wp = (WINDOW *) malloc(sizeof(WINDOW)); /* First window         */
  247.  
  248.     if(Pmaster){
  249.     if (bp==NULL || wp==NULL)
  250.       return(0);
  251.     }
  252.     else{
  253.         if (bp==NULL || wp==NULL || blistp==NULL)
  254.       exit(1);
  255.     }
  256.  
  257.     curbp  = bp;                            /* Make this current    */
  258.     wheadp = wp;
  259.     curwp  = wp;
  260.     wp->w_wndp  = NULL;                     /* Initialize window    */
  261.     wp->w_bufp  = bp;
  262.     bp->b_nwnd  = 1;                        /* Displayed.           */
  263.     wp->w_linep = bp->b_linep;
  264.     wp->w_dotp  = bp->b_linep;
  265.     wp->w_doto  = 0;
  266.     wp->w_markp = NULL;
  267.     wp->w_marko = 0;
  268.  
  269.     if(Pmaster){
  270.     wp->w_toprow = COMPOSER_TOP_LINE;
  271.     wp->w_ntrows = term.t_nrow - COMPOSER_TOP_LINE - 2;
  272.     fillcol = (term.t_ncol > 80) ? 80 : term.t_ncol - 6;
  273.     }
  274.     else{
  275.         wp->w_toprow = 2;
  276.         wp->w_ntrows = term.t_nrow-4;           /* "-1" for mode line.  */
  277.     fillcol = term.t_ncol - 6;              /* set fill column */
  278.     }
  279.  
  280.     wp->w_force = 0;
  281.     wp->w_flag  = WFMODE|WFHARD;            /* Full.                */
  282. }
  283.  
  284.  
  285. /*
  286.  * This is the general command execution routine. It handles the fake binding
  287.  * of all the keys to "self-insert". It also clears out the "thisflag" word,
  288.  * and arranges to move it to the "lastflag", so that the next command can
  289.  * look at it. Return the status of command.
  290.  */
  291. execute(c, f, n)
  292. {
  293.     register KEYTAB *ktp;
  294.     register int    status;
  295.  
  296.     ktp = (Pmaster) ? &keytab[0] : &pkeytab[0];
  297.  
  298.     while (ktp->k_fp != NULL) {
  299.     if (ktp->k_code == c) {
  300.  
  301.         if(lastflag&CFFILL){
  302.         curwp->w_flag |= WFMODE;
  303.         if(Pmaster == NULL)
  304.           sgarbk = TRUE;
  305.         }
  306.  
  307.         thisflag = 0;
  308.         status   = (*ktp->k_fp)(f, n);
  309.         lastflag = thisflag;
  310.  
  311.         return (status);
  312.     }
  313.     ++ktp;
  314.     }
  315.  
  316.  
  317.     /*
  318.      * Check to make sure that we're not going to go off of the screen
  319.      * with our next character.  If so wrap the line...
  320.      * note: in pico,  fillcol and wrap-mode are always set and 
  321.      *      wrapword behaves somewhat differently
  322.      */
  323.     if(((llength(curwp->w_dotp)+2 >= term.t_ncol) 
  324.     || (c == ' ' && getccol(FALSE) > fillcol)) 
  325.        && (curwp->w_bufp->b_mode & MDWRAP))
  326.       wrapword();
  327.  
  328.  
  329.     if ((c>=0x20 && c<=0x7E)                /* Self inserting.      */
  330.         ||  (c>=0xA0 && c<=0xFE)) {
  331.  
  332.     if (n <= 0) {                   /* Fenceposts.          */
  333.         lastflag = 0;
  334.         return (n<0 ? FALSE : TRUE);
  335.     }
  336.     thisflag = 0;                   /* For the future.      */
  337.  
  338.     /* if we are in overwrite mode, not at eol,
  339.        and next char is not a tab or we are at a tab stop,
  340.        delete a char forword            */
  341.     if (curwp->w_bufp->b_mode & MDOVER &&
  342.         curwp->w_doto < curwp->w_dotp->l_used &&
  343.         (lgetc(curwp->w_dotp, curwp->w_doto) != '\t' ||
  344.          (curwp->w_doto) % 8 == 7))
  345.       ldelete(1, FALSE);
  346.  
  347.     /* do the appropriate insertion */
  348.     /* pico never does C mode, this is simple */
  349.     status = linsert(n, c);
  350.  
  351.     lastflag = thisflag;
  352.     return (status);
  353.     }
  354.     
  355.     if(c&CTRL)
  356.       emlwrite("\007Unknown Command: ^%c", c&0xff);
  357.     else
  358.       emlwrite("\007Unknown Command", NULL);
  359.  
  360.     lastflag = 0;                           /* Fake last flags.     */
  361.     return (FALSE);
  362. }
  363.  
  364.  
  365.  
  366. /*
  367.  * Fancy quit command, as implemented by Norm. If the any buffer has
  368.  * changed do a write on that buffer and exit emacs, otherwise simply exit.
  369.  */
  370. quickexit(f, n)
  371. {
  372.     register BUFFER *bp;    /* scanning pointer to buffers */
  373.  
  374.     bp = bheadp;
  375.     while (bp != NULL) {
  376.     if ((bp->b_flag&BFCHG) != 0    /* Changed.             */
  377.         && (bp->b_flag&BFTEMP) == 0) {    /* Real.                */
  378.         curbp = bp;        /* make that buffer cur    */
  379.         filesave(f, n);
  380.     }
  381.     bp = bp->b_bufp;            /* on to the next buffer */
  382.     }
  383.     wquit(f, n);                             /* conditionally quit   */
  384. }
  385.  
  386.  
  387.  
  388. /* 
  389.  * abort_composer - ask the question here, then go quit or 
  390.  *                  return FALSE
  391.  */
  392. abort_composer(f,n)
  393. {
  394.     switch(mlyesno("Cancelling will abandon your mail message.  Cancel", 
  395.             FALSE)){
  396.       case TRUE:
  397.     longjmp(finstate, COMP_CANCEL);
  398.     break;
  399.       case ABORT:
  400.     emlwrite("\007Cancel Aborted", NULL);
  401.     break;
  402.       default:
  403.     mlerase();
  404.     break;
  405.     }
  406.     return(FALSE);
  407. }
  408.  
  409.  
  410. /*
  411.  * suspend_composer - return to pine with what's been edited so far
  412.  */
  413. suspend_composer(f, n)
  414. {
  415.     longjmp(finstate, COMP_SUSPEND);
  416. }
  417.  
  418.  
  419.  
  420. /*
  421.  * Quit command. If an argument, always quit. Otherwise confirm if a buffer
  422.  * has been changed and not written out. Normally bound to "C-X C-C".
  423.  */
  424. wquit(f, n)
  425. {
  426.     register int    s;
  427.  
  428.     if(Pmaster){
  429.     /*
  430.      * if we're not in header, show some of it as we verify sending...
  431.      */
  432.     setmark(FALSE, 1);
  433.     if(ComposerTopLine == COMPOSER_TOP_LINE){
  434.         gotobob(FALSE, 1);
  435.         update();
  436.     }
  437.  
  438.     switch(mlyesno("Send message", TRUE)){
  439.       case TRUE:
  440.         longjmp(finstate, COMP_EXIT);
  441.         break;
  442.       case ABORT:
  443.         emlwrite("\007Send Message Aborted", NULL);
  444.         break;
  445.       default:
  446.         mlerase();
  447.         break;
  448.     }
  449.  
  450.     swapmark(FALSE, 1);
  451.     }
  452.     else{
  453.         if (f != FALSE                          /* Argument forces it.  */
  454.         || anycb() == FALSE                     /* All buffers clean.   */
  455.                         /* User says it's OK.   */
  456.         || (s=mlyesno("Modified buffer: Save before leaving", -1)) == FALSE) {
  457.                 vttidy();
  458.                 exit(0);
  459.         }
  460.  
  461.     if(s == TRUE){
  462.         if(filewrite(0,1) == TRUE)
  463.           wquit(1, 0);
  464.     }
  465.     else if(s == ABORT){
  466.         emlwrite("\007Exit Aborted");
  467.     }
  468.         return(s);
  469.     }
  470. }
  471.  
  472.  
  473. /*
  474.  * Abort.
  475.  * Beep the beeper. Kill off any keyboard macro, etc., that is in progress.
  476.  * Sometimes called as a routine, to do general aborting of stuff.
  477.  */
  478. ctrlg(f, n)
  479. {
  480.     (*term.t_beep)();
  481.     if (kbdmip != NULL) {
  482.     kbdm[0] = (CTLX|')');
  483.     kbdmip  = NULL;
  484.     }
  485.     emlwrite("Aborted");
  486.     return (ABORT);
  487. }
  488.  
  489.  
  490. /* tell the user that this command is illegal while we are in
  491.  *  VIEW (read-only) mode
  492.  */
  493. rdonly()
  494. {
  495.     (*term.t_beep)();
  496.     emlwrite("Key illegal in VIEW mode");
  497.     return(FALSE);
  498. }
  499.  
  500.  
  501.  
  502. /*
  503.  * reset all globals to their initial values
  504.  */
  505. func_init()
  506. {
  507.     extern int    vtrow;
  508.     extern int    vtcol;
  509.     extern int    lbound;
  510.     extern int    ttrow;
  511.     extern int    ttcol;
  512.  
  513.     /*
  514.      * re-initialize global buffer type variables ....
  515.      */
  516.     fillcol = (term.t_ncol > 80) ? 80 : term.t_ncol - 6;
  517.     eolexist = TRUE;
  518.     revexist = FALSE;
  519.     sgarbf = TRUE;
  520.     mpresf = FALSE;
  521.     mline_open = FALSE;
  522.     ComposerEditing = FALSE;
  523.  
  524.     /*
  525.      * re-initialize hardware display variables ....
  526.      */
  527.     vtrow = vtcol = lbound = 0;
  528.     ttrow = ttcol = HUGE;
  529.  
  530.     pat[0] = rpat[0] = '\0';
  531. }
  532.  
  533.  
  534. /*
  535.  * pico_help - help function for standalone composer
  536.  */
  537. pico_help(text, title, i)
  538. char *text[], *title;
  539. int i;
  540. {
  541.     register    int numline = 0;
  542.     char        **p;
  543.  
  544.     p = text;
  545.     while(*p++ != NULL) 
  546.       numline++;
  547.     return(wscrollw(COMPOSER_TOP_LINE, term.t_nrow-1, text, numline));
  548.  
  549. }
  550.  
  551.  
  552.  
  553. #if     TERMCAP
  554. /*
  555.  * zottree() - kills the key pad function key search tree
  556.  *                and frees all lines associated with it!!!
  557.  */
  558. zottree(nodeptr)
  559. struct    KBSTREE    *nodeptr;
  560. {
  561.     if(nodeptr != NULL){
  562.     zottree(nodeptr->left);
  563.     zottree(nodeptr->down);
  564.     free((char *) nodeptr);
  565.     }
  566. }
  567. #endif
  568.  
  569.  
  570. /*
  571.  * zotedit() - kills the buffer and frees all lines associated with it!!!
  572.  */
  573. zotedit()
  574. {
  575.     register BUFFER    *bp;
  576.     register WINDOW    *wp;
  577.     register LINE    *lp;
  578.     register int    s;
  579.  
  580.     /*
  581.      * clean up the lines and buffer ...
  582.      */
  583.     curbp->b_flag &= ~BFCHG;
  584.  
  585.     if ((s=bclear(curbp)) != TRUE)        /* Blow text away.      */
  586.       return(s);
  587.  
  588.     free((char *) wheadp);            /* clean up window */
  589.     wheadp = NULL;
  590.     curwp  = NULL;
  591.  
  592.     free((char *) bheadp);            /* clean up buffers */
  593.     bheadp = NULL;
  594.     curbp  = NULL;
  595.  
  596.     zotheader();                /* blast header lines */
  597.  
  598.     zotdisplay();                /* blast display buffers */
  599.  
  600. #if     TERMCAP
  601.     zottree(kpadseqs);
  602.     kpadseqs = NULL;
  603. #endif
  604. }
  605.